package ar.edu.itba.jMEBowling;

import ar.edu.itba.jMEBowling.levels.Level;

import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.scene.Node;
import com.jme.scene.shape.Arrow;
import com.jme.util.Timer;

public class ShotSpecification {

	private Arrow shotDirection;

	private int sign;
	private float levelCoefficient;

	private float xAngle;
	private float arm;

	private float maxLimitPosX;
	private float minLimitPosX;
	private final float xAngleLimit = (float) (Math.PI) / 8;
	private final float powMaxLimit = 10;
	private final float powMinLimit = 3;

	private final float maxPower = -40000;
	private final float minPower = -5000;
	private final float maxSidePower = 4000;
	private final float minSidePower = -4000;
	private final float maxUpPower = 5000;
	private final float minUpPower = -1000;

	private Vector3f backupLocation;
	private float backupWidth;
	private float backupLength;
	private Quaternion backupRotation;
	private Timer timer;

	private Node rootNode;

	public ShotSpecification(Vector3f center, float xBandwith, float armPos,
			Level level, Node rootNode, Timer timer) {
		this.timer = timer;
		this.shotDirection = new Arrow("shotArrow");
		this.shotDirection.setLocalTranslation(center.add(0, armPos, 0));
		this.shotDirection.setLocalScale(0.7f);
		this.shotDirection.updateGeometry(powMinLimit, 1);
		this.shotDirection.setLocalRotation(new Quaternion(new float[] {
				(float) -Math.PI / 2, 0, 0 }));
		this.maxLimitPosX = center.getX() + xBandwith / 2;
		this.minLimitPosX = center.getX() - xBandwith / 2;

		this.xAngle = this.shotDirection.getLocalRotation().y;
		this.arm = (float) -Math.PI / 2;
		this.rootNode = rootNode;

		this.levelCoefficient = level.getCoefficient();

		this.backupLocation = new Vector3f(center.add(0, armPos, 0));
		this.backupRotation = new Quaternion(new float[] {
				(float) -Math.PI / 2, 0, 0 });
		this.backupLength = this.shotDirection.getLength();
		this.backupWidth = this.shotDirection.getWidth();

		rootNode.attachChild(this.shotDirection);
		this.sign = 1;
	}

	public void reset() {
		this.shotDirection.setLocalTranslation(new Vector3f(backupLocation));
		this.shotDirection.setLocalRotation(new Quaternion(backupRotation));
		this.shotDirection.updateGeometry(backupLength, backupWidth);
		this.arm = (float) -Math.PI / 2;
		this.xAngle = this.shotDirection.getLocalRotation().y;
		System.out.println(this.shotDirection.getLocalTranslation());
	}

	public void xMovement() {

		float actualX = shotDirection.getLocalTranslation().getX();

		if (actualX > maxLimitPosX || actualX < minLimitPosX) {
			sign = -sign;
		}

		shotDirection.getLocalTranslation().setX(
				actualX + (sign * timer.getTimePerFrame() * levelCoefficient));
		shotDirection.updateRenderState();

	}

	public void xAngleMovement() {
		if (Math.abs(xAngle) > Math.abs(xAngleLimit)) {
			sign = -sign;
		}

		xAngle += (sign * timer.getTimePerFrame() * levelCoefficient / 3f);
		this.shotDirection.setLocalRotation(new Quaternion(new float[] {
				(float) -Math.PI / 2, xAngle, 0f }));
		shotDirection.updateRenderState();

	}

	public void armMovement() {
		if (Math.abs(arm - (-(float) Math.PI / 2)) > (float) Math.PI / 4) {
			sign = -sign;
		}

		arm += (sign * timer.getTimePerFrame() * levelCoefficient);
		this.shotDirection.setLocalRotation(new Quaternion(new float[] { arm,
				xAngle, this.shotDirection.getLocalRotation().z }));
		shotDirection.updateRenderState();

	}

	public void powerSelection() {
		float actualPow = shotDirection.getLength();
		if (actualPow > powMaxLimit || actualPow < powMinLimit) {
			sign = -sign;
		}
		// System.out.println("X Actual: " + actualX + " Limite x: "
		// + maxLimitPosX);
		this.shotDirection.updateGeometry(actualPow
				+ (sign * timer.getTimePerFrame() * 4 * levelCoefficient),
				shotDirection.getWidth());
		shotDirection.updateRenderState();
	}

	/* XANGLE */
	public float getXForce() {
		// System.out.println("Angle: " + xAngle);
		float value = getValueFromLine((float) (Math.PI) / 8,
				-(float) (Math.PI) / 8, minSidePower, maxSidePower, xAngle);
		// System.out.println("XForce: " + value);
		return value;

	}

	/* ARM ANGLE */
	public float getYForce() {
		// System.out.println("Arm: " + arm);
		float value = getValueFromLine(-(float) Math.PI * 3 / 4,
				-(float) Math.PI / 4, minUpPower, maxUpPower, arm);
		// System.out.println("Up Force: " + value);
		return value;
	}

	/* POWER */
	public float getZForce() {
		float value = getValueFromLine(powMinLimit, powMaxLimit, minPower,
				maxPower, shotDirection.getLength());
		// System.out.println("Power value: " + value);
		return value;
	}

	private float getValueFromLine(float x1, float x2, float y1, float y2,
			float x) {
		return ((y2 - y1) / (x2 - x1)) * (x - x1) + y1;
	}

	public void finishSelection() {
		this.rootNode.detachChild(shotDirection);

	}

	public Arrow getShotDirection() {
		return shotDirection;
	}

	public float getMaxLimitPosX() {
		return maxLimitPosX;
	}

	public float getMinLimitPosX() {
		return minLimitPosX;
	}

	public float getXAngle() {
		return xAngle;
	}

	public float getXAngleLimit() {
		return xAngleLimit;
	}

	public float getArm() {
		return arm;
	}

	public float getPowMaxLimit() {
		return powMaxLimit;
	}

	public float getPowMinLimit() {
		return powMinLimit;
	}

	public void setLevel(Level level) {
		this.levelCoefficient = level.getCoefficient();

	}

}
